# oyAssetManager.py by Erkan Ozgur Yilmaz (c) 2009
# 
# v0.0.3
# 
# Description :
# -------------
# This is a simple asset management system that deals with projects, sequences,
# and assets by holding the metadata in xml files right beside the asset file
# 
# The projects and sequences are considered as assets too. So they have metadata
# too...
# 
# 
# Version History :
# -----------------
# v0.0.3:
# - renamed the jobs, scene objects to project and sequence to follow a more
#   world wide scheme
# - added the ability to use the file name for metadata
# 
# v0.0.2:
# - changed the version number scheme
# - removed the AssetManager object to oyProjectManager.py, and probably this
#   class will be removed
# 
# v0.0.1.preAlpha:
# - development version
# 
# TODO List :
# -----------
# - AssetManager should be expanded to hold information about the users,
#   the assets that the users are attached to
#
# - Should use a database maybe, to quickly get the data, but this will
#   introduce some difficulties to the programming phase, though it will
#
# - it needs an unified interface written with pyQt
# ----------------------------------------------------------------------------



__version__ = "v0.0.3"



import sys,os,re,shutil
from xml.dom import minidom



class AssetBase(object):
    """This is the base class that introduces basic operations which is common
    for Project, Sequence and Asset classes
    """
   
    def __init__(self, fullPath):
      
        # check if the path exists
        if not os.path.exists ( fullPath ):
            raise IOError("file doesn't exists")
        
        # use a settings file or just use the name for metadata
        self._useSettingsFile = False
        self._dataSep = "-"
        
        # until the settings file is red the asset should be dirty
        self.isDirty = True
      
        # path variables
        self._path = Path()
      
        self._path._fullPath = ''
        self._path._path = ''
        self._path._name = ''
        self._path._baseName = ''
        self._path._extension = ''
        self._path._settingsFileName = ''
        self._path._settingsFilePath = ''
        self._path._settingsFileFullPath = ''
        
        # info variables
        self._info = Info()
        
        # info variables are object spesific
        # so let them be set in the derived classes
        
        self.initialize_path_variables( fullPath )
        self.initialize_info_variables()
        
        # if the settings file exists auto-read it
        self.read_settings()
        
        self.save_settings()
    
    
    
    def initialize_path_variables(self, fullPath ):
        fullPath = os.path.abspath(fullPath)
        
        #path variables
        self._path._fullPath = fullPath
        self._path._path = self._get_path_from_fullPath( fullPath )
        self._path._name = self._get_name_from_fullPath( fullPath )
        
        self._path._baseName = self._get_baseName_from_fullPath( fullPath )
        self._path._extension = self._get_extension_from_fullPath( fullPath )
        
        self._path._settingsFileName = self._get_settingsFileName_from_fullPath( fullPath )
        self._path._settingsFilePath = self._get_settingsFilePath_from_fullPath( fullPath )
        self._path._settingsFileFullPath = self._get_settingsFileFullPath_from_fullPath( fullPath )
        
        self.isDirty = True
    
    
    
    def initialize_info_variables(self):
        pass
    
    
    
    def read_settings(self):
        """reads an asset file by parsing its settings file or its name.
        
        if the asset doesn't have any settings file attached, the method
        tries to get the data from name
        
        if it couldn't get any data from the name returns without doing
        anything
        """
        
        if self._useSettingsFile:
            # check if the settings file exists
            if not self._check_file( self._path._settingsFileFullPath ):         
                self.parse_name()
            
            self.parse_settings()
        else:
            self.parse_name()
        
        self.isDirty = False
    
    
    
    def save_settings(self):
        """should be implemented in the inherited class
        """
        pass
    
    
    
    def parse_settings(self):
        """should be implemented in the inherited class
        """
        pass
    
    
    
    def parse_name(self):
        """should be implemented in the inherited class
        """
        pass
    
    
    
    def set_info_variables(self, **kwords):
        """sets the info variables which contain the variables : \n
        
        use get_empty_info_variables_dictionary to have a default dictionary filled with keys to prevent any keyErrors
        
        should be implemented in the inherited class
        """
        pass
    
    
    
    def get_empty_info_variables_dictionary(self):
        """returns a dictionary which has enough keys to be used with the assets
        set_info_variables method, the values are set to the default values
        
        should be implemented in the inherited class
        """
        pass
    
    
    
    def get_path_variables(self):
        """returns all the path variables as a dictionary
        """
        pathVariables = dict()
        
        pathVariables['fullPath'] = self._path._fullPath
        pathVariables['path'] = self._path._path
        pathVariables['name'] = self._path._name
        pathVariables['baseName'] = self._path._baseName
        pathVariables['extension'] = self._path._extension
        pathVariables['settingsFilePath'] = self._path._settingsFileFullPath
        pathVariables['settingsFileName'] = self._path._settingsFileName
        pathVariables['settingsFileFullPath'] = self._path._settingsFileFullPath
        
        return pathVariables
    
    
    
    def get_info_variables(self):
        """returns all the info variables as a dictionary
        should be implemented in inherited class
        """
        pass
    
    
    
    def print_info_variables(self):
        """prints the info variables all together in a nice format
        """
        jLen = 25
        infoVariables = self.get_info_variables()
        
        for info in infoVariables.keys():
            print str(info).ljust(jLen),' : %s' % infoVariables[info]
    
    
    
    def print_path_variables(self):
        """prints the path variables all together in a nice format
        """
      
        jLen = 25
        pathVariables = self.get_path_variables()
        
        for path in pathVariables.keys():
            print str(path).ljust(jLen),' : %s' % pathVariables[path]
    
    
    
    def _check_file( self, fileFullPath ):
        """utility method that checks if a file exists \n
        returns 0 if not
        returns 1 if it does
        """
        
        try:
            fileId = open(fileFullPath,'r')
        except IOError:
            return 0
        else:
            fileId.close()
            return 1
    
    
    
    def _create_folder(self, folderPath ):
        """utility method that creates a folder if it doesn't exists
        """
        assert isinstance(folderPath, str)
        
        if ( not os.path.exists(folderPath) ):
            os.makedirs(folderPath)
    
    
    
    def rename(self, newName):
        """renames both the asset and its settings file
        
        if useSettingsFile is False than renaming an asset is forbidden
        """
        
        if not self._useSettingsFile:
            return
        
        # both the asset file and the settings file should be renamed
        # and the settings file should be updated
        
        newFullPath = os.path.join( self._path._path, newName )
        newBaseName = self._get_baseName_from_fullPath( newFullPath )
        newSettingsFileFullPath = self._get_settingsFileFullPath_from_fullPath( newFullPath )
        
        os.rename( self._path._fullPath, newFullPath )
        os.rename( self._path._settingsFileFullPath, newSettingsFileFullPath )
        
        self.initialize_path_variables( newFullPath )
        #self.save_settings()
    
    
    
    def copy(self, newFullPath):
        """copies the asset to a new location with its settings file
        the new path can be a path or a fullPath which contains the file name too
        
        the destination directory should exist
        
        returns a new asset object represents the copied one
        
        if self._useSettings is False the copying an asset is forbidden
        
        TODO: add support for renaming while copying
        """
        
        if not self._useSettingsFile:
            return
        
        
        newFileFullPath = os.path.join( newPath, self._path._name )
        
        # copy the original file
        shutil.copy( self._path._fullPath, newFileFullPath )
        
        # just create an asset there
        # the settings file should be created automatically
        
        newAsset = Asset( newFileFullPath )
        newAsset.set_info_variables( **self.get_info_variables() )
        newAsset.save_settings()
        
        return newAsset
    
    
    
    def move(self, newPath):
        """moves the asset to a new location with its settings file
        new path should contain only the path name
        
        if _useSettingsFile is False moving an asset is forbidden
        """
        
        if not self._useSettingsFile:
            return
        
        newPath = os.path.abspath(newPath)
        
        newFullPath = os.path.join( newPath, self._path._name )
        newSettingsFilePath = self._get_settingsFilePath_from_fullPath( newFullPath )
        newSettingsFileFullPath = self._get_settingsFileFullPath_from_fullPath( newFullPath )
        
        # move the original file
        shutil.move( self._path._fullPath, newFullPath )
        
        # check and create .asm folder
        self._create_folder( newSettingsFilePath )
        
        # move the settings file
        shutil.move( self._path._settingsFileFullPath, newSettingsFileFullPath )
        
        self._path._fullPath = newFullPath
        
        # change the path variables
        self.initialize_path_variables( newFullPath )
        
        self.save_settings()
   
    
    
    def _get_path_from_fullPath(self, fullPath ):
        return os.path.dirname( fullPath )
    
    
    
    def _get_name_from_fullPath(self, fullPath):
        return os.path.basename( fullPath )
    
    
    
    def _get_baseName_from_fullPath(self, fullPath):
        name = self._get_name_from_fullPath(fullPath)
        return os.path.splitext(name)[0]
    
    
    
    def _get_extension_from_fullPath(self, fullPath):
        return os.path.splitext(fullPath)[1]
    
    
    
    def _get_settingsFilePath_from_fullPath(self, fullPath):
        path = self._get_path_from_fullPath(fullPath)
        return os.path.join( path, '.asm' )
    
    
    
    def _get_settingsFileName_from_fullPath(self, fullPath):
        baseName = self._get_baseName_from_fullPath( fullPath )
        return baseName + '.xml'
    
    
    
    def _get_settingsFileFullPath_from_fullPath(self, fullPath):
        settingsFileName = self._get_settingsFileName_from_fullPath(fullPath)
        settingsFilePath = self._get_settingsFilePath_from_fullPath(fullPath)
        return os.path.join(settingsFilePath, settingsFileName)
    
    
    
    def file_name_conditioner(self, fileName):
        """ conditions the file name by replacing the whitespaces and slashes and
        back slahes with underscore ("_") characters
        """
        assert isinstance(fileName, str)
        
        myTurkishDict = dict()
        
        myTurkishDict['\xc3\xa7'] = 'c'
        myTurkishDict['\xc4\x9f'] = 'g'
        myTurkishDict['\xc4\xb1'] = 'i'
        myTurkishDict['\xc3\xb6'] = 'o'
        myTurkishDict['\xc5\x9f'] = 's'
        myTurkishDict['\xc3\xbc'] = 'u'
        
        myTurkishDict['\xc3\x87'] = 'C'
        myTurkishDict['\xc4\x9e'] = 'G'
        myTurkishDict['\xc4\xb0'] = 'I'
        myTurkishDict['\xc3\x96'] = 'O'
        myTurkishDict['\xc5\x9e'] = 'S'
        myTurkishDict['\xc3\x9c'] = 'U'
        
        rx = re.compile('|'.join(map(re.escape, myTurkishDict)))
        def one_xlat(match):
            return myTurkishDict[match.group(0)]
        fileName = rx.sub( one_xlat, fileName)
        
        # make all uppercase
        fileName = fileName.upper()
        
        # replace all the white spaces and slashes
        # with underscore ("_") character
        pattern = re.compile('[\t\n\r\f\v\\\/ ]+')
        fileName = pattern.sub("_",fileName)
        
        #replace turkish characters
        return fileName






class Project(AssetBase):
    """This is the main class that holds the project data and manupulates
    the project variables
    
    A project object should have Sequence objects that it contains
    
    the server path should be red from the xml file under $(HOME)/.oyAssetManager.xml
    
    every project own settings should be placed in .asm folder in projects root folder
    with the file name .projects_settings.xml
    
    the .projectSettings.xml should contain the sequence names
    
    """
    
    
    
    def initialize_info_variables(self):      
        self._info._sequences = [Sequence] * 0
    
    
    
    def create_sequence(self, sequenceName, shots, structure):
        """creates a new sequence and returns a sequence object attached to that sequence
        """
        
        # sequences should be under the projects full path + sequence name
        newSequenceFullPath = os.path.join( self._path._fullPath, sequenceName )
        
        # create the folder and the hierarchy
        self._create_folder( newSequenceFullPath )
        
        newSequence = Sequence( newSequenceFullPath )
        
        newSequence.set_shots( shots )
        newSequence.set_structure( structure )
        newSequence.save_settings()
        
        self._info._sequences.append( newSequence )
        self.save_settings()
    
    
    
    def rescan_for_sequences(self):
        pass
    
    
    
    def get_sequences(self):
        return self._sequences
    
    
    
    def save_settings(self):
        
        if not self.isDirty:
            return
        # create the xml nodes
        
        # root
        rootNode = minidom.Element('root')
        
        # sequences
        sequencesNode = minidom.Element('sequences')
        sequencesNodeText = minidom.Text()
        sequencesNode.appendChild( sequencesNodeText )
        
        # write the sequence names to the node
        sequencesNodeText.data = '\n'.join( self.get_sequenceNames() )
        
        # create xml file
        xmlDoc = minidom.Document()
        
        rootNode.appendChild( sequencesNode )
        xmlDoc.appendChild( rootNode )
        
        try:
            xmlFile = open( self._path._settingsFileFullPath )
        except IOError:
            print "couldn't open the settings file"
        else:
            xmlDoc.writexml( xmlFile )
            xmlFile.close()
            self.isDirty = False
    
    
    
    def _parse_settings(self):
        #xmlDoc = minidom.parse( self._projectSettingsFileFullPath )
        
        #assert ( isinstance( xmlDoc, minidom.Document) )
        pass
    
    
    
    def get_sequenceNames(self):
        sequenceNames = [''] * 0
        for sequence in self.get_sequences():
            #assert(isinstance(sequence,Sequence))
            sequenceNames.append(sequence._info._name)
        return sequenceNames
    
    
    
    def get_sequences(self):
        return self._info._sequences






class Sequence(AssetBase):
    """The sequence object holds information about a sequence under a project
    
    The object should be initialized with the sequence full path
    
    The sequence information is kept in under .asm folder which is placed right
    beside the sequence folder with the sequenceName.xml file. This XML file
    contains
    information about:
    
    - the sequence name
    - the shot list
    - the asset types
    - the sequence structure
    
    AssetType objects shows the data type name, the relative folder path of that
    type to the sequence root etc.
    
    The sequence structure is kept in another XML file called
    _sequenceStructure.xml. This sequence structure file will be used to
    recreate the same structure for other projects or to determine where to add
    new shot folders.
    
    Program settings files also kept under the .asm folder with the
    programName.xml that shows the abilities in terms of dealing with asset types
    of the current program that uses the script
    
    
    THINKING ABOUT:
    
    The sequence object should be able to scan all the assets folder to get all
    the info about the assets under the current project, these information
    should be carried with Asset objects
    
    Ex sequence path:\n
    M:/PROJECTS_PATH/PROJECT_NAME/SEQUENCE_NAME
    M:/JOBs/JEMBEY/_CHARACTER_SETUP_
    
    the initial creation of the sequence is the responsibility of ProjectManager
    object or the project object ( didn't desided yet ), so whenever we create a
    sequence object the sequence should exists, thus the settings file, but the
    sequence it self should be able to edit its own settings file, for example
    it should be able to add new shots to its shot database, or it should be
    able to add new asset types, or I don't know may be it's only the
    AssetManagers duty to change these settings, I need to deside those things
    
    """
    
    
    
    def initialize_info_variables(self):
        self._info._name = ''
        self._info._shots = [''] * 0
        self._info._structure = [''] * 0
        self._info._assetTypes = [AssetType] * 0
    
    
    
    def save_settings(self):
        """saves all the info and some of the path variables in to an xml file
        
        the xml file is saved to self._path._settingsFileFullPath
        """
        # if there is no new data don't try to save it
        if not self.isDirty:
            return
        
        # create the XML nodes
        root = minidom.Element('root')
        
        sequenceSettingsNode = minidom.Element('sequence')
        
        # asset types
        assetTypesNode = minidom.Element('assetTypes')
        assetTypesNodeText = minidom.Text()
        assetTypesNode.appendChild( assetTypesNodeText )
        
        assetTypeSettingAsText = ''
        
        for assetObj in self._info._assetTypes:
            assetTypeSettingAsText += assetObj.typeName + ',' + assetObj.typePath + ',' + str(assetObj.shotDependent) + '\n'
        
        assetTypesNodeText.data = assetTypeSettingAsText
        
        # shots
        shotsNode = minidom.Element('shots')
        shotsNodeText = minidom.Text()
        shotsNodeText.data = '\n'.join( self._info._shots )
        shotsNode.appendChild( shotsNodeText )
        
        # structure
        structureNode = minidom.Element('structure')
        structureNodeText = minidom.Text()
        structureNodeText.data = '\n'.join( self._info._structure )
        structureNode.appendChild( structureNode )
        
        # sequence
        sequenceSettingsNode.appendChild( structureNode )
        sequenceSettingsNode.appendChild( assetTypesNode )
        sequenceSettingsNode.appendChild( shotsNode )
        
        sequenceSettingsNode.setAttribute('name',self._info._name)
        
        root.appendChild( sequenceSettingsNode )
        
        self._create_folder( self._path._settingsFilePath)
        
        try:
            xmlSettingsFile = open( self._path._settingsFileFullPath, 'w' )
        except IOError:
            print "couldn't open the settings file : %s" % self._path._settingsFileFullPath
            return
        
        xmlDoc = minidom.Document()
        
        xmlDoc.writexml( xmlSettingsFile )
        xmlSettingsFile.close()
    
    
    
    def parse_settings(self):
        """Parses the XML setigns file
        """
        settingsFileXML = minidom.parse( self._path._settingsFileFullPath )
        
        rootNode = settingsFileXML.childNodes[0]
        
        assert( isinstance( rootNode, minidom.Element))
        
        sequenceSettingsNode = rootNode.getElementsByTagName('sequence')[0]      
        assetTypesNode = rootNode.getElementsByTagName('assetTypes')[0]
        structureNode = rootNode.getElementsByTagName('structure')[0]
        shotsNode = rootNode.getElementsByTagName('shots')[0]
        
        assert( isinstance( sequenceSettingsNode, minidom.Element))      
        self._info._name = sequenceSettingsNode.getAttribute('name')
        
        self._info._assetTypes = [AssetType] * 0
        
        if len(assetTypesNode.childNodes) > 0:
            for aTypeAsText in assetTypesNode.childNodes[0].wholeText.split('\n'):
                data = aTypeAsText.split(',')
                self._info._assetTypes.append( AssetType(data[0],data[1],data[2]) )
        
        if len(structureNode.childNodes) > 0:
            self._info._structure = structureNode.childNodes[0].wholeText.split('\n')
        
        if len(shotsNode.childNodes) > 0:
            self._info._shots = shotsNode.childNodes[0].wholeText.split('\n')
    
    
    
    def set_shots(self, shots):
        self._info._shots = shots
    
    
    
    def set_structure(self, structure):
        self._info._structure = structure
    
    
    
    def add_asset_type(self, assetType):
        self._info._assetTypes.append(assetType)
        self.isDirty = True
    
    
    
    def set_asset_types(self, assetTypes):
        self._info._assetTypes = assetTypes
        self.isDirty = True
    
    
    
    def get_asset_types(self):
        return self._info._assetTypes
    
    
    
    def _get_structureFileName_from_sequenceFullPath(self, sequenceFullPath):
        return '_structure.xml'
    
    
    
    def _get_structureFilePath_from_sequenceFullPath(self, sequenceFullPath):
        return os.path.joint( sequenceFullPath, '.asm' )
    
    
    
    def _get_structureFileFullPath_from_sequenceFullPath(self, sequenceFullPath):
        structureFilePath = self._get_structureFilePath_from_sequenceFullPath( sequenceFullPath )
        structureFileName = self._get_structureFileName_from_sequenceFullPath( sequenceFullPath )
        return os.path.join( structureFilePath, structureFileName )
    
    
    
    def get_all_assets(self):
        """be carefull that it scans all the directory structure of the current
        sequence
        """
        pass
    
    
    
    def get_cached_assets(self):
        """uses the last scan result to return the Assets
        """
        pass
    
    
    
    def _save_sequence_settings_as_template(self, templateFullPath):
        pass
    
    
    
    def get_program_abilities(self):
        pass
    
    
    
    def get_shot_folders(self):
        shotDatabaseFolderName = '_shotDatabaseFolder'
        
        shot_folders = [''] * 0
        
        for path in self._info._structure:
            if path[-len(shotDatabaseFolderName):] == shotDatabaseFolderName:
                shot_folders.append( path )
        
        return shot_folders






class Asset(AssetBase):
    """This is the class that will deal with assets, simply all individual
    files that asset manager deals with.
    
    So it should have the file paths for the specific file and the xml file
    that the file is connected to ( or the xml file that holds the metadata about
    the original file )
    
    fileFullPath should contain both the path and file name
    for the asset
    
    Ex:
    M:/JOBs/JEMBEY/_CHARACTER_SETUP_/_RIG_/JemBey/JemBey-RIG-r00-v104-oy.ma
    
    so we can guess that the settings file is inside the .asm folder right
    beside the original file
    
    M:/JOBs/JEMBEY/_CHARACTER_SETUP_/_RIG_/JemBey/.asm/JemBey-RIG-r00-v104-oy.xml
    
    for Asset to work the file should exists before the Asset object
    """
    
    shotPrefix = "SH"
    shotPadding = 3
    
    revisionPrefix = "r"
    revisionPadding = 2
    
    versionPrefix = "v"
    versionPadding = 3
    
    
    def initialize_info_variables(self):
        self._info._shot = 0
        self._info._shotString = ''
        self._info._assetBaseName = ''
        self._info._assetSubName = ''
        self._info._assetType = ''
        self._info._revision = 0
        self._info._revisionString = ''
        self._info._version = 0
        self._info._versionString = ''
        self._info._user = ''
        self._info._notes = ''
        self._info._dependencies = [''] * 0
    
    
    
    def set_info_variables(self, **kwords):
        """sets the info variables which contain the variables : \n
        shotString
        assetBaseName
        assetSubName
        assetType
        revision
        version
        user
        notes
        
        use get_empty_info_variables_dictionary to have a default dictionary filled with keys to prevent any keyErrors
        """
        assert( isinstance(kwords,dict))
        
        self._info._shot = kwords['shot']
        self._info._assetBaseName = kwords['assetBaseName']
        self._info._assetSubName = kwords['assetSubName']
        self._info._assetType = kwords['assetType']
        self._info._revision = kwords['revision']
        self._info._version = kwords['version']
        self._info._user = kwords['user']
        self._info._notes = kwords['notes']
        
        self._info._dependencies = kwords['dependencies']
        
        # create the settings file
        #self.save_settings()
        self.isDirty = True
    
    
    
    def get_empty_info_variables_dictionary(self):
        """returns a dictionary which has enough keys to be used with the assets
        set_info_variables method, the values are set to the default values
        """
        infoVariables = dict()
        infoVariables['shot'] = ''
        infoVariables['assetBaseName'] = ''
        infoVariables['assetSubName'] = ''
        infoVariables['assetType'] = ''
        infoVariables['revision'] = ''
        infoVariables['version'] = ''
        infoVariables['user'] = ''
        infoVariables['notes'] = ''
        infoVariables['dependencies'] = ['']*0
        
        return infoVariables
    
    
    
    def get_info_variables(self):
        """returns all the info variables as a dictionary
        """
        
        infoVariables = dict()
  
        infoVariables['shot'] = self._info._shot
        infoVariables['assetBaseName'] = self._info._assetBaseName
        infoVariables['assetSubName'] = self._info._assetSubName
        infoVariables['assetType'] = self._info._assetType
        infoVariables['revision'] = self._info._revision
        infoVariables['version'] = self._info._version
        infoVariables['user'] = self._info._user
        infoVariables['notes'] = self._info._notes
        infoVariables['dependencies'] = self._info._dependencies
        
        return infoVariables
    
    
    
    def save_settings(self):
        """saves all the info and some of the path variables in to an xml file
        
        the xml file is saved to self._path._settingsFileFullPath
        """
        
        # if the object uses its name don't create a settings file
        if not self._useSettingsFile:
            self.isDirty = False
            return
        
        # if there is no new data don't try to save it
        if not self.isDirty:
            return
       
        # create the XML nodes
        root = minidom.Element('root')
        
        assetSettingsNode = minidom.Element('asset')
        root.appendChild(assetSettingsNode)
        
        assetSettingsNode.setAttribute("shot", self._info._shot)
        assetSettingsNode.setAttribute("assetBaseName", self._info._assetBaseName)
        assetSettingsNode.setAttribute("assetSubName", self._info._assetSubName)
        assetSettingsNode.setAttribute("assetType", self._info._assetType)
        assetSettingsNode.setAttribute("revision", self._info._revision)
        assetSettingsNode.setAttribute("version", self._info._version)
        assetSettingsNode.setAttribute("user", self._info._user)
        assetSettingsNode.setAttribute("notes", self._info._notes)
        
        dependencySettingNode = minidom.Element('dependencies')
        root.appendChild( dependencySettingNode )
        
        dependencySettingNodeText = minidom.Text()
        
        dependencySettingNode.appendChild( dependencySettingNodeText )
        
        dependencySettingNodeText.data = "\n".join(self._info._dependencies)
        
        self._create_folder( self._path._settingsFilePath)
        
        assetSettingsXML = minidom.Document()
        assetSettingsXML.appendChild(root)
        
        try:
            assetSettingsFile = open( self._path._settingsFileFullPath , 'w' )
        except IOError:
            print "couldn't open the settings file"
        else:
            #print assetSettingsXML.toprettyxml()
            assetSettingsXML.writexml( assetSettingsFile )
            assetSettingsFile.close()
            self.isDirty = False
    
    
    
    def parse_settings(self):
        """Parses the XML settings file which is under the ".asm" folder right beside
        the original file
        """
        
        # check if the asset uses a settings file
        if not self._useSettingsFile:
            return
        
        settingsFileXML = minidom.parse( self._path._settingsFileFullPath )
        
        rootNode = settingsFileXML.childNodes[0]
        
        rootChildren = rootNode.childNodes
        
        assetSettingNode = rootChildren[0]
        
        dependencySettingNode = rootChildren[1]
        
        self._info._shot = assetSettingNode.getAttribute('shot')
        self._info._assetBaseName = assetSettingNode.getAttribute('assetBaseName')
        self._info._assetSubName = assetSettingNode.getAttribute('assetSubName')
        self._info._assetType = assetSettingNode.getAttribute('assetType')
        self._info._revision = assetSettingNode.getAttribute('revision')
        self._info._version = assetSettingNode.getAttribute('version')
        self._info._user = assetSettingNode.getAttribute('user')
        self._info._notes = assetSettingNode.getAttribute('notes')
        
        self._info._dependencies = [''] * 0
        #read the dependencies
        if len(dependencySettingNode.childNodes) > 0:
            self._info._dependencies = dependencySettingNode.childNodes[0].wholeText.split('\n')
    
    
    
    def parse_name(self):
        """Parse the name of the file to get the data
        
        data should be in this order:
        
        assetBaseName / shotString
        assetSubName
        assetType
        revision
        version
        user
        notes
        
        """
        
        dataString = self._path._baseName
        assert(isinstance(dataString,str))
        
        rawData = dataString.split( self._dataSep )
        
        self._info._shotString = self._info._assetBaseName = rawData[0]
        self._info._assetSubName = rawData[1]
        self._info._assetType = rawData[2]
        self._info._revString = rawData[3]
        self._info._verString = rawData[4]
        self._info._user = rawData[5]
        
        if len(rawData) > 6 ):
            self._info._notes = rawData[6]
        else:
            self._info._notes = ""
    
    
    
    def set_shot(self, shot):
        """sets shot
        """
        self._info._shot = shot
        self.isDirty = True
    
    
    
    def set_assetBaseName(self, assetBaseName):
        """sets the assetBaseName
        """
        self._info._assetBaseName = assetBaseName
        self.isDirty = True
    
    
    
    def set_assetSubName(self, assetSubName):
        """sets the assetSubName
        """
        self._info._assetSubName = assetSubName
        self.isDirty = True
    
    
    
    def set_assetType(self, assetType):
        """sets the assetType
        """
        self._info._assetType = assetType
        self.isDirty = True
    
    
    
    def set_revision(self, revision):
        """sets revision number
        """
        self._info._revision = revision
        self.isDirty = True
    
    
    
    def set_version(self, version):
        """sets version number
        """
        self._info._version = version
        self.isDirty = True
    
    
    
    def set_user(self, user):
        """sets user initials
        """
        self._info._user = user
        self.isDirty = True
    
    
    
    def set_notes(self, notes):
        """sets notes
        """
        self._info._notes = notes
        self.isDirty = True
    
    
    
    def set_dependencies(self, dependencies):
        """sets dependencies
        """
        self._info._dependencies = dependencies
        self.isDirty = True
    
    
    
    def add_dependencies(self, newDependency):
        """adds dependencies to the asset
        """
        self._info._dependencies.append( os.path.abspath(newDependency) )
        self.isDirty = True
    
    
    
    def get_shot(self):
        """returns shot
        """
        return self._info._shot
    
    
    
    def get_assetBaseName(self):
        """returns the assetBaseName
        """
        return self._info._assetBaseName
    
    
    
    def get_assetSubName(self):
        """returns assetSubName
        """
        return self._info._assetSubName
    
    
    
    def get_assetType(self):
        """returns assetType
        """
        return self._info._assetType
    
    
    
    def get_revision(self):
        """returns revision number
        """
        return self._info._revision
    
    
    
    def get_version(self):
        """returns version number
        """
        return self._info._version
    
    
    
    def get_user(self):
        """returns user intials
        """
        return self._info._user
    
    
    
    def get_notes(self):
        """returns notes
        """
        return self._info._notes
    
    
    
    def get_fileBaseName(self):
        """returns fileBaseName
        """
        return self._path._baseName
    
    
    
    def get_extension(self):
        """returns extension
        """
        return self._path._extension
    
    
    
    def get_dependencies(self):
        """returns dependencies as a list
        """
        return self._info._dependencies
    
    
    
    def increase_version(self):
        """increases the version number
        """
        self.set_version( self.get_version() + 1 )
        self.isDirty = True
    
    
    
    def increase_revision(self):
        """increases the revision number
        """
        self.set_revision( self.get_revision() + 1 )
        self.isDirty = True
    
    
    
    def decrease_version(self):
        """decreases the version number and prevents going below zero
        """
        if self.get_version() > 1:
            self.set_version( self.get_version() - 1 )
    
    
    
    def decrease_revision(self):
        """decreases the revision number and prevents going below zero
        """
        if self.get_revision() > 1:
            self.set_revision( self.get_revision() - 1 )
    
    
    
    def get_all_versions(self):
        """returns a list of asset objects for all previous versions of this asset
        """
        # get the
        pass






class Path(object):
    pass






class Info(object):
    pass






class AssetType(object):
    """Holds data like:\n
    - the asset type name
    - relative path of that type
    - the shot dependency of that AssetType
    """
    def __init__(self, typeName='', typePath='', shotDependent=False):
        self.typeName = typeName
        self.typePath = typePath
        self.shotDependent = shotDependent






class StatusCode(object):
    """holds data for asset status
    """
    def __init__(self, currentStatusCode='0'):
        self.currentStatus = statusCode
        
        self.statusCode = dict()
        
        self.statusCode['0'] = 'on hold'
        self.statusCode['1'] = 'waiting to start'
        self.statusCode['2'] = 'ready to start'
        self.statusCode['3'] = 'in progress'
        self.statusCode['4'] = 'final'






class User(object):
    """holds user information
    """






class UserType(object):
    """holds user type information
    """
    def __init__(self, userType='0'):
        pass
